package com.csx.governance.traffic.adapter.inbound.webmvc;

import com.csx.governance.traffic.core.context.TrafficContext;
import com.csx.governance.traffic.core.context.TrafficContextHolder;
import com.csx.governance.traffic.core.context.TrafficRequest;
import com.csx.governance.traffic.core.context.TrafficResponse;
import com.csx.governance.traffic.core.context.servlet.TrafficHttpServletRequest;
import com.csx.governance.traffic.core.context.servlet.TrafficHttpServletResponse;
import com.csx.governance.traffic.core.interceptor.TrafficHandlerInterceptorRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Tomcat Servlet 入栈, 通过 {@link TrafficHandlerInterceptorRunner} 调用一系列 InboundHandlerInterceptor
 * @author cuisongxu
 * @date 2023/2/22 19:07
 */
public class TrafficSwimLaneServletFilter implements Filter {

    private final Logger logger = LoggerFactory.getLogger(TrafficSwimLaneServletFilter.class);

    private final TrafficHandlerInterceptorRunner handlerInterceptorRunner;

    public TrafficSwimLaneServletFilter(TrafficHandlerInterceptorRunner handlerInterceptorRunner) {
        this.handlerInterceptorRunner = handlerInterceptorRunner;
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        if(!(servletRequest instanceof HttpServletRequest)
            || !(servletResponse instanceof HttpServletResponse)) {
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        Exception ex = null;
        TrafficHttpServletRequest trafficHttpServletRequest = new TrafficHttpServletRequest((HttpServletRequest) servletRequest);
        TrafficHttpServletResponse trafficHttpServletResponse = new TrafficHttpServletResponse((HttpServletResponse) servletResponse);
        // 将 请求对象 和 响应对象 保存在上下文中
        buildContext(trafficHttpServletRequest, trafficHttpServletResponse);
        try {
            handlerInterceptorRunner.preHandle(trafficHttpServletRequest, trafficHttpServletResponse);
            filterChain.doFilter(servletRequest, servletResponse);
            handlerInterceptorRunner.postHandle(trafficHttpServletRequest, trafficHttpServletResponse);
        } catch (Exception e) {
            ex = e;
            logger.error("TrafficSwimLaneServletFilter doFilter error because: {}", e.getMessage());
            throw e;
        } finally {
            handlerInterceptorRunner.afterCompletion(trafficHttpServletRequest, trafficHttpServletResponse, ex);
        }
    }

    private void buildContext(TrafficRequest request, TrafficResponse response) {
        TrafficContext trafficContext = new TrafficContext(request, response);
        TrafficContextHolder.setContext(trafficContext);
    }
}
